/*
* TacticaIgnacio.java
*
* Created on 17 de julio de 2006, 22:26
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/

package futbol.tacticas.concursantes2007.CRCW;
import futbol.General;
import futbol.tacticas.concursantes.Tactica;

import java.awt.*;
import java.util.Vector;
import futbol.tacticas.*;
/**
 *
 * @author Administrador
 */
public class TacticaIgnacio3 implements Tactica{
    private final double DISTANCIA_SEGURIDAD = 10;

    private final int BORDE_X_AREA = -110;
    private final int BORED_X_CIRCULO = -55;


    private boolean avanzando = true;
    private int contadorDebug = 0;

    // Este contador lo utilizo para que las llamadas a buscar jugadores cercanos a uno dado
    // solo se hagan que X turnos, de esta manera evito que los jugadores se vuelvan "locos"
    // cambiando de jugador al que tienen que tapar/del que se tiene que desmarcar continuamente
    private int contadorBuscaCercano = 0;

    // Fuerza 5 -> 98 pixels app

    private int relacionFuerza = 10;
    private Point lastPosBola = new Point(0,0);

    private int nValores[][]={
        {-150,0,4},  //  portero
        {-70,-90,5},  // Jugador 2[1]
        {-90,30,5},  // Jugador 3[2]
        {-90,-30,5},  // Jugador 4[3]
        {-70,90,5},  // Jugador 5[4]
        {-30,-40,5},  // Jugador 6[5]
        {-30,40,4},  // Jugador 7[6]
        {55,0,5},  // Jugador 8[7]
        {80,80,7},  // Jugador 9[8]
        {80,-80,7},  // Jugador 10[9]
        {100,0,6}  // Jugador 11[10]
    };

    private int enemigosCercanos[]={0,1,2,3,4,5,6,7,8,9,10};

    private int j4MaxX, j4MaxY, j4MinX, j4MinY;
    private int j3MaxX, j3MaxY, j3MinX, j3MinY;

    public TacticaIgnacio3(){
        super();
        j4MaxX = -30;
    }

    public Color getColor1() {
        return Color.yellow;
    }

    public Color getColor2() {
        return Color.blue;
    }

    public Color getColorNumero() {
        return Color.black;
    }

    public String getNombre() {
        return "CRCW";
    }

    public int getXInicial(int n) {
        return nValores[n][0];
    }

    public int getYInicial(int n) {
        return nValores[n][1];
    }

    public int getFuerza(int n) {
        return nValores[n][2];
    }

    /**
     * Creo la ecuacion de la recta que pasa por dos puntos. Y miro si algun jugador
     * contrario esta en las cercanas de esa recta
     */
    private boolean isPaseTapado(Point origen, Point destino, Point[] contrario ){
        for(int i=0;i<contrario.length;i++){
            Point jugador = contrario[i];
            if(isBetween(origen, destino, jugador)){
                return true;
            }
        }
        return false;
    }

    private Comando golpearBola(int iJugador, SituacionJugadores sj){
        // buscamos al jugador mas adelantado
        Point porteria = new Point(160,0);
        int iJugadorAdelantado = sj.getMiJugadorMasCerca(160, 0);
        int contador = 0;
        int jugadoresProbados[] = new int[11];
        jugadoresProbados[contador] = iJugadorAdelantado;
        while(iJugadorAdelantado >= 0 && isPaseTapado(sj.getBola(), sj.getMisJugadores()[iJugadorAdelantado], sj.getContrario()) && contador <= 10){
            contador++;
            int info[] = sj.getInfoMasCercano(sj.getMisJugadores(), porteria, jugadoresProbados , false);
            iJugadorAdelantado = info[0];
            jugadoresProbados[contador]=iJugadorAdelantado;
        }
        if(contador > 10 || iJugadorAdelantado<0)
            return new ComandoTiroAPuerta(iJugador, 0);

        else
            return comandoPasar(sj, iJugador, iJugadorAdelantado);
    }

    private double moverPorteroX(Point bola){
        double x = bola.getX();
        double xDis = Math.abs(x - nValores[0][0]);

        double diffY = bola.getY() - lastPosBola.getY();

        if(xDis <= 30 && Math.abs(bola.getY()) < 30)
            return Math.max(-160, x-8);
        else
            return nValores[0][0];
    }

    private double moverPorteroY(Point bola){
        double y = adivinaYSegunX(lastPosBola, bola, -160);
        if(bola.getX() >= lastPosBola.getX())
            y = bola.getY();

        if(y > 30)
            return 30;
        if(y < -30)
            return -30;

        return y;
    }

    private int adivinaYSegunX(Point punto1, Point punto2, double posX){
        return (int)(punto1.getY()+( (punto2.getY() - punto1.getY()) * (posX-punto2.getX()) / (punto2.getX() - punto1.getX()) ));
    }

    private int adivinaXSegunY(Point punto1, Point punto2, double posY){
        return (int)(( (posY - punto1.getY()) * (punto2.getX() - punto1.getX()) / (punto2.getY() - punto1.getY()) ) + punto1.getX());
    }

    private Point taparJugador(SituacionJugadores sj, int enemigo){
        Point bola = sj.getBola();
        Point posEne = sj.getContrario()[enemigo];
        if(bola.getX() == lastPosBola.getX() && bola.getY() == lastPosBola.getY())
            return posEne;

        int posX = (int)(posEne.getX()-10);
        int posY = adivinaYSegunX(bola, posEne, posX);
        Point destino = new Point(posX, posY);
        if(!isBetween(bola, posEne, destino)){
            posX = (int)(posEne.getX()+10);
            posY = adivinaYSegunX(bola, posEne, posX);
            destino = new Point(posX, posY);
            if(!isBetween(bola, posEne, destino)){
                posY = (int)(posEne.getY()+10);
                posX = adivinaXSegunY(bola, posEne, posY);
                destino = new Point(posX, posY);
                if(!isBetween(bola, posEne, destino)){
                    posY = (int)(posEne.getY()-10);
                    posX = adivinaXSegunY(bola, posEne, posY);
                    destino = new Point(posX, posY);
                }
            }
        }

        return destino;
    }

    private boolean isInArea(Point jugador){
        if(jugador.getX()<-90 && jugador.getY()<70 &&jugador.getY()>-70)
            return true;
        return false;
    }

    private int estoyMasCercaDe(int iJugadorOrigen, int iJugador1, int iJugador2, SituacionJugadores sj){
        Point yo = sj.getMisJugadores()[iJugadorOrigen];
        Point j1 = sj.getMisJugadores()[iJugador1];
        Point j2 = sj.getMisJugadores()[iJugador2];

        double d1 = yo.distance(j1);
        double d2 = yo.distance(j2);

        return d1<=d2?1:2;
    }

    private Comando paseDefensasCentrales(SituacionJugadores sj, int jugador){
        Point miPos = sj.getMisJugadores()[jugador];
        Point posLateral1 = sj.getMisJugadores()[1];
        Point posLateral4 = sj.getMisJugadores()[4];
        Point posMedio5 = sj.getMisJugadores()[5];
        Point posMedio6 = sj.getMisJugadores()[6];
        int opcion1=1, opcion2=4;
        int jugadorElegido = -1;

        if(jugador == 3){
            posLateral1 = sj.getMisJugadores()[4];
            posLateral4 = sj.getMisJugadores()[1];
            opcion1=4;opcion2=1;
        }

        if(!isPaseTapado(miPos, posMedio6,sj.getContrario()))
            jugadorElegido = 6;
        else if(!isPaseTapado(miPos, posMedio5, sj.getContrario()))
            jugadorElegido = 5;
        else if(!isPaseTapado(miPos, posLateral1, sj.getContrario()))
            jugadorElegido=opcion1;
        else if(!isPaseTapado(miPos, posLateral4, sj.getContrario()))
            jugadorElegido=opcion2;

        if(jugadorElegido>0){
            if(miPos.distance(sj.getMisJugadores()[jugadorElegido])>20)
                return new ComandoPase(jugador, jugadorElegido);
        }
        return new ComandoTiroAPuerta(jugador, 0);
    }

    private Comando paseDelPortero(SituacionJugadores sj){
        return lanzarBolaMejor(sj);
    }

    private boolean estoyCubierto(SituacionJugadores sj, int iJugador){
        Point yo = sj.getMisJugadores()[iJugador];
        Point bola = sj.getBola();
        int iContrario = sj.getContrarioMasCerca(iJugador);
        Point contrario = sj.getContrario()[iContrario];
        if(yo.distance(contrario) < 10){
            if (contrario.getX() > yo.getX() && bola.getX() > yo.getX())
                return true;
            if (contrario.getX() < yo.getX() && bola.getX() < yo.getX())
                return true;
        }
        return false;
    }

    private Comando desmarcarse(SituacionJugadores sj, int iJugador, int signo){
        Point yo = sj.getMisJugadores()[iJugador];
        double movimiento = ((Math.random()*40)-20);
        double x = yo.getX()+movimiento;
        movimiento = ((Math.random()*40)-20);
        double y = yo.getX()+movimiento;

        return new ComandoIrA(iJugador, x, y);
    }

    private Vector getJugadoresEnRango(SituacionJugadores sj, int iJugador){
        double distanciaMax = getFuerza(iJugador)*this.relacionFuerza;
        double distanciaMin = 10;
        int par = iJugador%2;
        Point yo = sj.getMisJugadores()[iJugador];
        Vector listaJugadores = new Vector();
        Point[] jugadores = sj.getMisJugadores();
        for(int i=jugadores.length-1;i>0;i--){
            if(i%2 == par && i != iJugador){
                double distancia = yo.distance(jugadores[i]);
                if(distancia<=distanciaMax && distancia > distanciaMin && !estoyCubierto(sj, i))
                    listaJugadores.add(new Integer(i));
            }
        }

        return listaJugadores;
    }

    private Comando comandoPasar(SituacionJugadores sj, int origen, int destino){
        Point posOrigen = sj.getMisJugadores()[origen];
        Point posDestino = sj.getMisJugadores()[destino];
        if(posOrigen.getX() > posDestino.getX())
            return new ComandoTiroAPuerta(origen, 0);
        else
            return new ComandoPase(origen, destino);

    }

    private Comando llevarBalon(SituacionJugadores sj, int jugador){
        int nDir[][]={{30,0},
                      {0,30},
                      {0,-30}};
        int nDis=30;

        Point bola = sj.getBola();
        Point posJugador = sj.getMisJugadores()[jugador];
        Point[] ene = sj.getContrario();

        int iSiguiente = sj.getSiguienteJugador(jugador);
        if (iSiguiente < 0)
            iSiguiente = 10;
        Point next = sj.getMisJugadores()[iSiguiente];
        double distanciaNext = posJugador.distance(next);
        if(distanciaNext < 70){

            return new ComandoGolpearBola(jugador, next.getX(), next.getY());

        }

        if (General.getDistancia(bola.getX(), bola.getY(), posJugador.getX(), posJugador.getY())<10)
            for (int n=0;n<nDir.length ;n++){
                double xN=corregirLateral(160,posJugador.getX()+nDir[n][0]);
                double yN=corregirLateral(120,posJugador.getY()+nDir[n][1]);
                int nJC= sj.getContrarioMasCerca(xN, yN);
                if (General.getDistancia(xN, yN, ene[nJC].getX(), ene[nJC].getY())>nDis){
                    return new ComandoGolpearBola(jugador, xN, yN);
                }
            }
        return null;

    }

    private double corregirLateral(double limite, double x){
        if (x>limite) return limite*2-x;
        if (x<-limite) return -limite*2-x;
        return x;
    }

    private Comando decidirPase(SituacionJugadores sj, int origen, int dest1, int dest2){
        Point miPos = sj.getMisJugadores()[origen];
        Point dest1Pos = sj.getMisJugadores()[dest1];
        Point dest2Pos = sj.getMisJugadores()[dest2];

        double dist1 = miPos.distance(dest1Pos);
        double dist2 = miPos.distance(dest2Pos);
        if(dist1 > 100){
            if(dist2 > dist1)
                return new ComandoPase(origen, dest1);
            else
                return new ComandoPase(origen, dest2);
        }
        if(dist2 > 100){
            if(dist1 > dist2)
                return new ComandoPase(origen, dest2);
            else
                return new ComandoPase(origen, dest1);
        }
        if(estoyCubierto(sj, dest1))
            return new ComandoPase(origen, dest2);
        if(estoyCubierto(sj, dest2))
            return new ComandoPase(origen, dest1);
        if(dist1 < dist2)
            return new ComandoPase(origen, dest2);
        else
            return new ComandoPase(origen, dest1);
    }

    private boolean isBetween(Point pos1, Point pos2, Point punto){
        int y1 = (int)pos1.getY();
        int x1 = (int)pos1.getX();
        int x2 = (int)pos2.getX();
        int y2 = (int)pos2.getY();

        java.awt.Polygon rect = new Polygon();
        rect.addPoint(x1,y1);
        rect.addPoint(x1,y2);
        rect.addPoint(x2,y2);
        rect.addPoint(x2,y1);

        if(rect.contains(punto))
            return true;
        return false;
    }

    private double heuristica(SituacionJugadores sj, int x, int y){
        int nHeu=-Math.abs(y*100)-Math.abs(x*100);
        Point jugadores[]=sj.getMisJugadores();
        for (int n=0;n<11;n++){
            int nDis=(int)(General.getDistancia(x,y,jugadores[n].getX(), jugadores[n].getY()));
            if (nDis<30)
                nHeu-=300;
        }

        Point contrarios[]=sj.getContrario();
        Point dest = new Point(x,y);
        int[] cercano = sj.getInfoMasCercano(contrarios, new Point(x,y), null, false);
        if(cercano[1]<70)
            return 9999999;
        for (int n=0;n<11;n++){
            if(isBetween(sj.getMisJugadores()[0], dest, contrarios[n]))
                return 9999999;
        }
        return nHeu;
    }

    private Comando lanzarBolaMejor(SituacionJugadores sj){
        double nHeuMejor=9999999;
        int xMej=190, yMej=0;
        int x=0, y=0;
        double nHeu;
        for(int n=0;n<sj.getMisJugadores().length;n++){
            x=(int)sj.getMisJugadores()[n].getX();
            y=(int)sj.getMisJugadores()[n].getY();
            nHeu=heuristica(sj,x,y);
            if (nHeuMejor>nHeu){
                nHeuMejor=nHeu;
                xMej=x;
                yMej=y;
            }
        }
        for (int n=0;n<50;n++){
            x=(int)(Math.random()*150)+60;
            y=(int)(Math.random()*240)-120;
            nHeu=heuristica(sj,x,y);
            if (nHeuMejor>nHeu){
                nHeuMejor=nHeu;
                xMej=x;
                yMej=y;
            }
        }
        return new ComandoGolpearBola(0, xMej, yMej);
    }

    public Vector<Comando> getComandos(SituacionJugadores sj) {
        Vector<Comando> com=new Vector();
        //Posicionamiento
        int correccionX = 0;
        int correccionY = 0;
        Point bola = sj.getBola();

        if (bola.getX() < 0)
            correccionX = -20;
        else
            correccionX = 20;
        if (bola.getY() > 0)
            correccionY = 10;
        else
            correccionY = -10;

        // Movimiento general de los jugadores
        for (int n=0;n<11;n++)
            if(n != 1 && n!=4)
                com.add(new ComandoIrA(n,nValores[n][0]+correccionX,nValores[n][1]+correccionY));
            else
                com.add(new ComandoIrA(n,nValores[n][0],nValores[n][1]));


        // Movimiento de los centrales
        if(contadorBuscaCercano == 0){
            int delanteros1[] = sj.getInfoMasCercano(sj.getContrario(), sj.getMisJugadores()[0], null, false);
            int[] excluir = {delanteros1[0]};
            int delanteros2[] = sj.getInfoMasCercano(sj.getContrario(), sj.getMisJugadores()[0], excluir, false);
            Point def2 = sj.getMisJugadores()[2];
            Point def3 = sj.getMisJugadores()[3];

            Point posDel1 = sj.getContrario()[delanteros1[0]];
            Point posDel2 = sj.getContrario()[delanteros2[0]];
            if(def2.distance(posDel1) < def3.distance(posDel1)){
                enemigosCercanos[2]=delanteros1[0];
                enemigosCercanos[3]=delanteros2[0];
            }
            else{
                enemigosCercanos[2]=delanteros2[0];
                enemigosCercanos[3]=delanteros1[0];
            }
        }
        contadorDebug=++contadorDebug%10;
        if(contadorDebug == 9)
            contadorDebug = 9;
        Point destDef2;
        Point destDef3;

        destDef2 = taparJugador(sj, enemigosCercanos[2]);
        destDef3= taparJugador(sj, enemigosCercanos[3]);
        if(destDef2.getX()>-55){
            destDef2.setLocation(nValores[2][0], nValores[2][1]);
        }
        if(destDef3.getX()>-55){
            destDef3.setLocation(nValores[3][0], nValores[3][1]);
        }

        com.add(new ComandoIrA(2, destDef2.getX(), destDef2.getY()));
        com.add(new ComandoIrA(3, destDef3.getX(), destDef3.getY()));

        // Si la bola esta en el area, los defensores centrales van a por ella
        if(isInArea(bola)){
            com.add(new ComandoIrA(2, bola.getX(), bola.getY()));
            com.add(new ComandoIrA(3, bola.getX(), bola.getY()));
        }



        // Movimiento de los jugadores laterales para ir a por el balon
        if(bola.getX()<0 && bola.getY() < -70)
            com.add(new ComandoIrA(1, bola.getX(), bola.getY()));


        if(bola.getX()<0 && bola.getY() > 70)
            com.add(new ComandoIrA(4, bola.getX(), bola.getY()));


        // Movimiento de los centrocampistas para ir a por el balon

        if (bola.getX() > -85 && bola.getX() < -10){
            if(bola.getY() > -70 && bola.getY() < 70)
                com.add(new ComandoIrA(5, bola.getX(), bola.getY()));
        }


        if (bola.getX() > -10 && bola.getX() < 70){
            if(bola.getY() < 70 && bola.getY() > -70)
                com.add(new ComandoIrA(6, bola.getX(), bola.getY()));
        }


        // Movimiento de los laterales para desmarcarse
        if(bola.getX() < 0){
            if(estoyCubierto(sj, 7))
                com.add(desmarcarse(sj, 7, -1));
        }
        else{
            if(bola.getY() < -55)
                com.add(new ComandoIrA(7, bola.getX(), bola.getY()));
            else{
                if (bola.getX() > sj.getMisJugadores()[7].getX())
                    com.add(new ComandoIrA(7, bola.getX()+10, -55));
                else
                    com.add(new ComandoIrA(7, nValores[7][0], -55));
            }
        }

        // Movimiento para ir a por la bola
        int iJugadorCercano = sj.getMasCercanoDeBola();
        if(iJugadorCercano != 0)
            com.add(new ComandoIrA(iJugadorCercano, bola.getX(), bola.getY()));

        int otroJugador = iJugadorCercano;
        if(sj.getMisJugadores()[iJugadorCercano].distance(bola) > 10)
            otroJugador = sj.getSiguienteJugador(iJugadorCercano);

        if(otroJugador != 0 && otroJugador != iJugadorCercano)
            com.add(new ComandoIrA(otroJugador, bola.getX(), bola.getY()));

        // Estrategia de los delanteros
        if(iJugadorCercano == 10 || iJugadorCercano == 9 || sj.getContrario()[0].getY()>20 || sj.getContrario()[0].getY()<-20)
            com.add(new ComandoTiroAPuerta(iJugadorCercano, 0));

        // Estrategia defensores centrales
        else if(iJugadorCercano == 2 || iJugadorCercano == 3){
            com.add(paseDefensasCentrales(sj, iJugadorCercano));
        }

        // Estrategia defensores laterales
        else if(iJugadorCercano == 1){
            Vector jugadores = getJugadoresEnRango(sj, iJugadorCercano);
            if(jugadores.size() > 0){
                com.add(comandoPasar(sj, iJugadorCercano, (Integer)jugadores.get(0)));
            }
            else
                com.add(new ComandoTiroAPuerta(iJugadorCercano,0));
        }
        else if(iJugadorCercano == 4){
            Vector jugadores = getJugadoresEnRango(sj, iJugadorCercano);
            if(jugadores.size() > 0){
                com.add(comandoPasar(sj, iJugadorCercano, (Integer)jugadores.get(0)));
            }
            else
                com.add(new ComandoTiroAPuerta(iJugadorCercano,0));
        }

        // Estrategia Centrocampistas
        else if(iJugadorCercano == 5 || iJugadorCercano == 6 || iJugadorCercano == 7){
            Comando comando = llevarBalon(sj, iJugadorCercano);
            if (comando != null)
                com.add(comando);
            else{
                Vector jugadores = getJugadoresEnRango(sj, iJugadorCercano);
                if(jugadores.size() > 0){
                    int iDestino =(Integer)jugadores.get(0);
                    if(iDestino <= iJugadorCercano)
                        iDestino = iJugadorCercano+2;

                    com.add(comandoPasar(sj, iJugadorCercano, iDestino));
                }
                else
                    com.add(new ComandoTiroAPuerta(iJugadorCercano,0));
            }
        }

        else if (iJugadorCercano != 0){
            if(bola.distance(160,0) <= 60)
                com.add(new ComandoTiroAPuerta(iJugadorCercano, 0));
            else
                com.add(comandoPasar(sj, iJugadorCercano, 10));
        }

        if(iJugadorCercano == 0)
            iJugadorCercano = 0;
        com.add(new ComandoIrA(0, moverPorteroX(bola), moverPorteroY(bola)));
        com.add(paseDelPortero(sj));

        lastPosBola = bola;
        contadorBuscaCercano=++contadorBuscaCercano%10;        

        return com;
    }

}
